<?php

namespace App\Trip\Orders\BookOrders\Params;

use App\Models\Passengers\Passenger;
use App\Models\Passengers\Repositories\Interfaces\PassengerRepositoryInterface;
use App\Trip\IdentityCode\IdentityCode;
use App\Trip\Orders\BookOrders\BookTypes;
use App\Trip\Orders\BookOrders\Params\AbstractPassengersParam\AbstractPassengersParam;
use App\Trip\Passengers\OrderSubPassenger;
use App\Trip\Passengers\Passengers;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;

class PassengersParam extends AbstractPassengersParam
{
    const RECEIVE_PARAM_FIELDS
        = [
            'passenger_id', 'sequence',
            'identity_code', 'identity_type',
            'passenger_type', 'truename', 'mobile',
        ];
    private array     $passenger_data;
    private BookTypes $bookType;
    private string    $user_id;

    public function __construct(array $param, BookTypes $bookType)
    {
        $this->setPassengerData($param)->setBookType($bookType);
    }

    public function setBookType(BookTypes $bookType): static
    {
        $this->bookType = $bookType;
        return $this;
    }

    private function setPassengerData(array $param): static
    {
        $this->passenger_data = collect($param)->map(fn($passenger) => collect($passenger)->only(self::RECEIVE_PARAM_FIELDS)->toArray())->toArray();
        return $this;
    }

    public function getPassengerIds(): array
    {
        // 改签可能用的是子乘客ID
        return collect(array_column($this->passenger_data, 'passenger_id'))->map(function ($passenger_id) {
            $p = OrderSubPassenger::parsePassengerId($passenger_id);
            return $p['passenger_id'];
        })->toArray();
    }

    /**
     * @throws Exception
     */
    public function getParamPassengers(): array
    {
        $passengers            = $this->passenger_data;
        $valid_passenger_types = Passenger::getPassengerTypeString();
        $valid_identity_types  = Passenger::getIdentityTypeString();
        $validator             = Validator::make($passengers, [
            '*.truename'       => "required",
            '*.passenger_id'   => "required",
            '*.identity_code'  => "required",
            '*.identity_type'  => "required|in:{$valid_identity_types}",
            '*.mobile'         => "required|phone",
            '*.passenger_type' => "required|in:{$valid_passenger_types}",
        ], [
            "*.identity_type.in"                         => "证件类型错误",
            "*.passenger_type.in"                        => "乘客类型错误",
            "*.identity_code.passengers_identify_number" => "证件号错误",
        ]);

        if ($validator->fails()) {
            Log::error("BookOrderManager:getPassengers:{$validator->errors()->first()}");
            throw new Exception($validator->errors()->first());
        }

        // 验证乘客数量
        if (empty($passengers) || count($passengers) > 5) {
            throw new Exception("乘客数量错误");
        }

        // 学生成人重复验证
        $has_children    = false;
        $has_adult       = false;
        $passenger_types = array_count_values(array_column($passengers, 'passenger_type'));
        if (isset($passenger_types[Passengers::PASSENGER_TYPE_CHILD]) || isset
            ($passenger_types[Passengers::PASSENGER_TYPE_CHILD2])) {
            $has_children = true;
        }

        if (isset($passenger_types[Passengers::PASSENGER_TYPE_ADULT])) {
            $has_adult = true;
        }
        // 购票和抢票的情况
        if ($this->bookType->isBook() || $this->bookType->isSnapUp()) {
            // 验证儿童票是否单独出行
            if ($has_children && !$has_adult) {
                // 儿童票不能单独购买 可以改签~~
                throw new Exception("儿童不能单独出行，请于成人票一同购买");
            }
        }

        /**
         * @var $passenger_info Passenger
         */
        $repeat_checks  = [];
        $passengerRepo  = app(PassengerRepositoryInterface::class);
        $passengers_tmp = [];
        foreach ($passengers as $key => $passenger) {
            $subData      = OrderSubPassenger::parsePassengerId($passenger['passenger_id']);
            $passenger_id = $subData['passenger_id'];
            if (!isset($passengers_tmp[$passenger_id])) {
                $passenger_info = $passengerRepo->findOneByPassengerIdAndUserId($passenger_id, $this->user_id);
                if (!$passenger_info) {
                    throw new Exception("乘客不存在".":{$passenger['truename']}");
                }
                $passengers_tmp[$passenger_id] = $passenger_info;
            } else {
                $passenger_info = $passengers_tmp[$passenger_id];
            }

            $sequence                             = $subData['sequence'] ?: ($passenger['sequence'] ?? "");
            $passengers[$key]['sub_passenger_id'] = $passenger['passenger_id'];
            $passengers[$key]['passenger_id']     = $passenger_id;
            $passengers[$key]['sequence']         = $sequence;
            $passengers[$key]['sex']              = $passenger_info->getGender();
            $passengers[$key]['birth_day']        = $passenger_info->getBirthDay();
            $passengers[$key]['age']              = $passenger_info->getAge();
            $identity_code                        = $passenger_info->getIdentityCode();
            if ($passenger['identity_type'] != $passenger_info->getIdentityType()) {
                throw new Exception("乘客证件类型错误".":{$passenger['truename']}");
            }

            if ($passenger_info->getTrueName() != $passenger['truename']) {
                throw new Exception("乘客姓名发生变化".":{$passenger['truename']}");
            }

            if (1 == $passenger['identity_type'] && $identity_code !== $passenger['identity_code']) {
                $idc = new IdentityCode($identity_code);
                if (!($idc->hide(2, 2) == $passenger['identity_code'] || $idc->hide(6, 2) == $passenger['identity_code'])) {
                    throw new Exception("乘客证件号发生变化".":{$passenger['truename']}");
                }
            }
            $passengers[$key]['identity_code'] = $identity_code;
            // 验证(成人、学生、残|军)乘客是否重复
            if (!in_array($passenger['passenger_type'], Passengers::ChildrenTypes())) {
                if (isset($repeat_checks[$passenger_id])) {
                    throw new Exception("乘客重复".":{$passenger['truename']}");
                }
                $repeat_checks[$passenger_id] = $passenger_id;
            }

        }
        return $passengers;
    }

    public function setUserId(string $user_id): void
    {
        $this->user_id = $user_id;
    }
}